package com.example.log.converter;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.example.log.util.DesensitizerUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

import java.io.IOException;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日志脱敏类
 */
@Slf4j
public class DeSensitizerConverter extends MessageConverter {

//    private static final String sensitiveDataKeys = "\"password\",\"phone\",\"email\",mail,emailChannel,has deal message";
    private static final String sensitiveDataKeys = "password,phone,email,mail,emailChannel,has deal message";

    @Override
    public String convert(ILoggingEvent event) {
//        String originLogMsg = event.getFormattedMessage();
//        Level level = event.getLevel();
//        if(Level.ERROR.equals(level)){
//            // 获取脱敏后的日志
//            try {
//                originLogMsg = logMsgProcessor(originLogMsg);
//            } catch (Exception e) {
//                // 不做任何操作，直接返回原数据
//                e.printStackTrace();
//            }
//        }
//        return originLogMsg;
        try {
            return logMsgProcessor(event.getFormattedMessage());
        }catch (Exception e){
            e.printStackTrace();
            //如果脱密过程出现异常，说明格式和我们预想的不一样，或者根本找不到对应value，原值返回即可
            return event.getFormattedMessage();
        }


//        return event.getFormattedMessage();
    }

    /**
     * 处理日志字符串，返回脱敏后的字符串
     */
    public String logMsgProcessor(String originLogMsg){
        if(Boolean.parseBoolean(getProperty("logback.sensitiveDataConverter.enabled")) && StringUtils.isNotBlank(sensitiveDataKeys)){
            String[] keysArray = sensitiveDataKeys.split(",");
            for(String key: keysArray){
//                    originLogMsg = repetitiveKeys(originLogMsg, key, 0);
                int index= -1;
                do{
                    //如果等于-1，则说明没有找到key
                    index = originLogMsg.indexOf(key, index+1);
                    if(index != -1){
                        //如果在日志中发现了key，判断是不是我们指定的key
                        if(isSingleWord(originLogMsg, key, index)){
                            continue;
                        }
                        // 寻找值的开始位置
                        int valueStartIndex = getValueStartIndex(originLogMsg, index + key.length());
                        // 查找值的结束位置
                        int valueEndIndex = getValueEndEIndex(originLogMsg, valueStartIndex);
                        // 对获取的值进行脱敏
                        String valueStr = originLogMsg.substring(valueStartIndex, valueEndIndex);
                        originLogMsg = originLogMsg.substring(0,valueStartIndex) + desensitizer(key,valueStr) + originLogMsg.substring(valueEndIndex);
                        //并非所有日志是json
//                        int jsonMark = originLogMsg.indexOf("{");
//                        if(jsonMark != -1){
//                            // 寻找值的开始位置
//                            int valueStartIndex = getValueStartIndex(originLogMsg, index + key.length());
//                            // 查找值的结束位置
//                            int valueEndIndex = getValueEndEIndex(originLogMsg, valueStartIndex);
//                            // 对获取的值进行脱敏
//                            String valueStr = originLogMsg.substring(valueStartIndex, valueEndIndex);
//                            originLogMsg = originLogMsg.substring(0,valueStartIndex) + desensitizer(key,valueStr) + originLogMsg.substring(valueEndIndex);
//                        }else{
//                            //key后第一个空格的索引
//                            int lSpaceIndex = originLogMsg.indexOf(" ", index + key.length() + 1);
//                            //key对应的value结尾
//                            if(lSpaceIndex != -1){
//                                String value = originLogMsg.substring(index + key.length() + 1,lSpaceIndex);
//                                originLogMsg =  originLogMsg.substring(0,index + key.length() + 1) + desensitizer(key, value) + originLogMsg.substring(lSpaceIndex);
//                            }else {
//                                String value = originLogMsg.substring(index + key.length() + 1);
//                                originLogMsg =  originLogMsg.substring(0,index + key.length() + 1) + desensitizer(key, value);
//                            }
//                        }
                    }
                }while(index != -1);
            }
        }

        return originLogMsg;
    }

//    public String repetitiveKeys(String originLogMsg, String key, int keyStartIndex){
//        try {
//            int jsonIndex = originLogMsg.indexOf("{\"");
//            //从{"a":"b"}中找到a出现的位置，又或者是a b的情况
//            keyStartIndex = originLogMsg.indexOf(key, keyStartIndex == 0 ? 0 : keyStartIndex + key.length());
//            if(keyStartIndex == -1){
//                //1.没有找到；2.递归结束
//                return originLogMsg;
//            }
//            //如果处理的字段不是处于日志中的json部分，则需要单独处理
//            if (jsonIndex == -1){
//                //key后第一个空格的索引
//                int lSpaceIndex = originLogMsg.indexOf(" ", keyStartIndex + key.length() + 1);
//                String value = originLogMsg.substring(keyStartIndex + key.length() + 1,lSpaceIndex);
//                String desensitizerResult = desensitizer(key, value);
//                String prefix = originLogMsg.substring(0,keyStartIndex + key.length() + 1);
//                String suffix = originLogMsg.substring(lSpaceIndex);
//                originLogMsg =  prefix + desensitizerResult + suffix;
//                return originLogMsg;
//            }else {
//                //如果处理的字段处于日志中的json部分
//                //找到keyStartIndex后第一个':'出现的位置
//                int colonIndex = originLogMsg.indexOf(":", keyStartIndex);
//                //找到keyStartIndex后第一个','出现的位置，如果没有','说明报文结束了，那就找到'}'的位置
//                int commaIndex = originLogMsg.indexOf(",", keyStartIndex) == -1 ? originLogMsg.indexOf("}", keyStartIndex) : originLogMsg.indexOf(",", keyStartIndex);
//                //找到key对应的value，该值即为需要脱敏的值
//                String value = originLogMsg.substring(colonIndex + 2,commaIndex - 1);
//                //脱敏处理
//                String desensitizerResult = desensitizer(key, value);
//                String prefix = originLogMsg.substring(0,keyStartIndex + key.length() + 3);
//                String suffix = originLogMsg.substring(commaIndex - 1);
//                originLogMsg =  prefix + desensitizerResult + suffix;
//                //如果日志json中含有重复的key，则递归处理
//                return repetitiveKeys(originLogMsg, key, keyStartIndex);
//            }
//        }catch (Exception e){
//            e.printStackTrace();
//            return originLogMsg;
//        }
//
//    }

    public String getProperty(String key) {
        try {
            Properties properties = PropertiesLoaderUtils.loadProperties(new ClassPathResource("application.properties"));
            return properties.getProperty(key);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String desensitizer(String key, String value){
        if("password".equals(key)){
            return DesensitizerUtils.dePassword();
        }
        if("phone".equals(key)){
            return DesensitizerUtils.deMobilePhone(value);
        }
        if("email".equals(key) || "mail".equals(key) || "emailChannel".equals(key) || "has deal message".equals(key)){
            return DesensitizerUtils.deEmail(value);
        }
        return value;
    }

    private static Pattern pattern = Pattern.compile("[0-9a-zA-Z]");
    /**
     * 判断从字符串msg获取的key值是否为单词 ， index为key在msg中的索引值
     */
    private boolean isSingleWord(String originLogMsg, String key, int index){

        // 如果index为0，说明前面没有任何元素
        if(index != 0){
            // 判断key前面一个字符
            char preCh = originLogMsg.charAt(index-1);
            Matcher match = pattern.matcher(preCh + "");
            if(match.matches()){
                return true;
            }
        }
        // 排除关键字是否是字符串结尾的情况
        if(index + key.length() < originLogMsg.length()){
            // 判断key后面一个字符
            char nextCh = originLogMsg.charAt(index + key.length());
            Matcher match = pattern.matcher(nextCh + "");
            if(match.matches()){
                return true;
            }
        }
        return false;
    }

    /**
     * 获取value值的开始位置
     * valueStart: index + key.length()
     */
    private int getValueStartIndex(String originLogMsg, int valueStart ){
        // 寻找值的开始位置
        do{
            if(valueStart == originLogMsg.length()){
                break;
            }
            char ch = originLogMsg.charAt(valueStart);
            if(ch == ':' || ch == '=' || ch == ' '){ // key与 value的分隔符
                valueStart ++;
                ch = originLogMsg.charAt(valueStart);
                if(ch == '"'){
                    valueStart ++;
                }
                break;    // 找到值的开始位置
            }else{
                valueStart ++;
            }
        }while(true);
        return valueStart;
    }

    /**
     * 获取value值的结束位置
     * valueEndIndex: valueStartIndex
     */
    private int getValueEndEIndex(String originLogMsg,int valueStartIndex){
        do{
            if(valueStartIndex == originLogMsg.length()){
                break;
            }
            char ch = originLogMsg.charAt(valueStartIndex);

            if(ch == '"'){ // 引号时，判断下一个值是结束，分号还是逗号决定是否为值的结束
                if(valueStartIndex+1 == originLogMsg.length()){
                    break;
                }
                char nextCh = originLogMsg.charAt(valueStartIndex+1);
                if(nextCh ==';' || nextCh == ','){
                    // 去掉前面的 \  处理这种形式的数据
                    while(valueStartIndex>0 ){
                        char preCh = originLogMsg.charAt(valueStartIndex-1);
                        if(preCh != '\\'){
                            break;
                        }
                        valueStartIndex--;
                    }
                    break;
                }else{
                    valueStartIndex ++;
                }
            }else if (ch ==';' || ch == ',' || ch == '}'){
                break;
            }else{
                valueStartIndex ++;
            }

        }while(true);
        return valueStartIndex;
    }

}
